//
//  iCamerDevice.m
//  AppControllerDevices
//
//  Created by joker on 15/8/7.
//  Copyright (c) 2015年 joker. All rights reserved.
//
#import "Configuration.h"
#import "iCamerClient.h"

#import <sys/time.h>

#import "IOTCAPIs.h"
#import "AVAPIs.h"
#import "AVIOCTRLDEFs.h"
#import "AVFRAMEINFO.h"

#include "MPEG2AAC_ADTSTYPE.mm"

@interface iCamerClient()
{
        //视频解码缓冲同步锁与缓冲数组
    NSLock *lock;
    NSMutableArray * bufferArray;
    
        //音频解码缓冲同步锁与缓冲数组
    NSLock *audioLock;
    NSMutableArray *audioBufferArray;
    
        //播放AAC信息记录变量
    MyData myData;
}
    //音视频解码想着私有属性
@property  int SessionID;
@property  int ChannelIndex;
@property BOOL LoginSuccessfully;
@property BOOL  isVideoStart;
@property BOOL  isAudioStart;

@end

@implementation iCamerClient
    //MARK: 辅助函数区
unsigned long GetTickCount() {
    
    struct timeval tv;
    
    if (gettimeofday(&tv, NULL) != 0)
        return 0;
    
    return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
    //视频解码辅助函数
-(void)displayImage:(UIImage *)image {
    [self.delegate updateView:image];
}
-(UIImage *)convertImageWithAVFrameRGB:(AVFrame *) frameRGB Width: (int)width Height:(int)height {
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8*)frameRGB->data[0], frameRGB->linesize[0]*height,kCFAllocatorNull);
    CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    CGImageRef cgImage = CGImageCreate(width,
                                       height,
                                       8,
                                       24,
                                       frameRGB->linesize[0],
                                       colorSpace,
                                       bitmapInfo,
                                       provider,
                                       NULL,
                                       YES,
                                       kCGRenderingIntentDefault);
    CGColorSpaceRelease(colorSpace);
    
    UIImage *image =[UIImage imageWithCGImage:cgImage ];
    
    CGImageRelease(cgImage);
    CGDataProviderRelease(provider);
    CFRelease(data);
    
    return image;
}

    //MARK: 接口函数
-(void)ConnectDeviceWithUID:(NSString *)uid UserName:(NSString *)name PassWord:(NSString *)passwd{
    self.DeviceUID = uid;
    self.UserName = name;
    self.PassWord = passwd;

    [NSThread detachNewThreadSelector:@selector(Login) toTarget:self withObject:nil];

}
-(void)Login{
    
    self.LoginSuccessfully = NO;
    
    NSLog(@"AVStream Client Login Device Start ...");
    
    unsigned short nUdpPort = (unsigned short)(10000 + (GetTickCount() % 10000));
    
    int ret = IOTC_Initialize(nUdpPort,P2PHostNamePrimary, P2PHostNameSecondary, P2PHostNameThird, P2PHostNameFourth);
    
    NSLog(@"IOTC_Initialize() ret = %d", ret);
    
    if (ret != IOTC_ER_NoERROR) {
        NSLog(@"IOTC_Initalize() error! ");
        [self CancelConnectDevice];
        return;
    }
    
    ret = avInitialize(MaxChannelNum);
    if(ret < 0 )
    {
        NSLog(@"avInitialize() error!");
        [self CancelConnectDevice];
        return;
    }
    
    self.SessionID = IOTC_Connect_ByUID((char *)[self.DeviceUID UTF8String]);
    
    NSLog(@"IOTC_Connect_ByUID(%s)  SID(%d).......\n", [self.DeviceUID UTF8String], self.SessionID);
    
    
    struct st_SInfo Sinfo;
    ret = IOTC_Session_Check(self.SessionID, &Sinfo);
    
    if (ret >= 0)
    {
        if(Sinfo.Mode == 0)
            printf("Device is from %s:%d[%s] Mode=P2P\n",Sinfo.RemoteIP, Sinfo.RemotePort, Sinfo.UID);
        else if (Sinfo.Mode == 1)
            printf("Device is from %s:%d[%s] Mode=RLY\n",Sinfo.RemoteIP, Sinfo.RemotePort, Sinfo.UID);
        else if (Sinfo.Mode == 2)
            printf("Device is from %s:%d[%s] Mode=LAN\n",Sinfo.RemoteIP, Sinfo.RemotePort, Sinfo.UID);
    }
    
    unsigned int srvType;
    
    self.ChannelIndex = avClientStart(
                                      self.SessionID,
                                      [self.UserName UTF8String],
                                      [self.PassWord UTF8String],
                                      20000,
                                      &srvType,
                                      0
                                      );
    
    NSLog(@"The server Type is %08x %08x %08x %08x",srvType >> 24 & 0xff, srvType >> 16 &0xff,
          srvType >> 8 & 0xff, srvType >> 0 & 0xff);
    
    NSLog(@"avClientStart(%d).......\n", self.ChannelIndex);
    
    if(self.ChannelIndex < 0)
    {
        printf("avClientStart failed[%d]\n", self.ChannelIndex);
        [self CancelConnectDevice];
        return;
    }
    
    self.LoginSuccessfully = YES;
    
        //登录成功后启用指令回应检测线程
    [NSThread detachNewThreadSelector:@selector(RecvIOCtrlLoop) toTarget:self withObject:nil];
    return;
}
-(void)RecvIOCtrlLoop{
    
    unsigned int ioType;
    char trash[1500];
    int ret;
    
    SMsgAVIoctrlSetAudioFormatResp* audioFormatInfo;
    SMsgAVIoctrlSetStreamCtrlResp* streamFormatInfo;
    
    SMsgAVIoctrlGetAudioOutFormatResp * audioOutFormat;
    SMsgAVIoctrlGetStreamCtrlResq * streamQuality;
    
    while (self.LoginSuccessfully) {
        
        ret = avRecvIOCtrl(self.ChannelIndex, &ioType, trash, sizeof(trash), 10000);
        if(ret == AV_ER_INVALID_ARG){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_INVALID_ARG");
        }else if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_SESSION_CLOSE_BY_REMOTE");
        }else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_REMOTE_TIMEOUT_DISCONNECT");
        }else if( ret == AV_ER_INVALID_SID){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_INVALID_SID");
        }else if( ret == AV_ER_DATA_NOREADY){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_DATA_NOREADY");
        }else if( ret == AV_ER_TIMEOUT){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_TIMEOUT");
        }else if( ret == AV_ER_BUFPARA_MAXSIZE_INSUFF){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_BUFPARA_MAXSIZE_INSUFF");
        }else if (ret == AV_ER_NO_PERMISSION){
            NSLog(@"[RecvIOCtrlLoop] - AV_ER_NO_PERMISSION");
        }
        else if(ret >= 0){
            switch (ioType) {
                case IOTYPE_USER_IPCAM_SETAUDIOFORMAT_RESP:
                    NSLog(@"[RecvIOCtrlLoop] - IOTYPE_USER_IPCAM_SETAUDIOFORMAT_RESP");
                    audioFormatInfo= (SMsgAVIoctrlSetAudioFormatResp*)trash;
                    if(audioFormatInfo->result == 0)
                    {
                        NSLog(@"设置音频格式成功");
                        
                    }else{
                        NSLog(@"设置音频格式失败");
                    }
                    break;
                case IOTYPE_USER_IPCAM_SETSTREAMCTRL_RESP:
                    NSLog(@"[RecvIOCtrlLoop] - IOTYPE_USER_IPCAM_SETSTREAMCTRL_RESP");
                    streamFormatInfo = (SMsgAVIoctrlSetStreamCtrlResp* )trash;
                    if (streamFormatInfo->result == 0) {
                        NSLog(@"设置视频流质量成功");
                    }else
                    {
                        NSLog(@"设置视频流质量失败");
                    }
                    break;
                case IOTYPE_USER_IPCAM_GETAUDIOOUTFORMAT_RESP:
                    audioOutFormat = (SMsgAVIoctrlGetAudioOutFormatResp *)trash;
                    if(audioOutFormat->channel == self.ChannelIndex)
                    {
                        switch (audioOutFormat -> format) {
                            case MEDIA_CODEC_UNKNOWN:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_UNKNOWN");
                                break;
                            case MEDIA_CODEC_VIDEO_MPEG4:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_VIDEO_MPEG4");
                                break;
                            case MEDIA_CODEC_VIDEO_H263:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_VIDEO_H263");
                                break;
                            case MEDIA_CODEC_VIDEO_H264:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_VIDEO_H264");
                                break;
                            case MEDIA_CODEC_VIDEO_MJPEG:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_VIDEO_MJPEG");
                                break;
                            case MEDIA_CODEC_AUDIO_AAC:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_AAC");
                                break;
                            case MEDIA_CODEC_AUDIO_G711U:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_G711U");
                                break;
                            case MEDIA_CODEC_AUDIO_G711A:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_G711A");
                                break;
                            case MEDIA_CODEC_AUDIO_ADPCM:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_ADPCM");
                                break;
                            case MEDIA_CODEC_AUDIO_PCM:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_PCM");
                                break;
                            case MEDIA_CODEC_AUDIO_SPEEX:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_SPEEX");
                                break;
                            case MEDIA_CODEC_AUDIO_MP3:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_MP3");
                                break;
                            case    MEDIA_CODEC_AUDIO_G726:
                                NSLog(@"[Audio Out Format] - MEDIA_CODEC_AUDIO_G726");
                                break;
                            default:
                                NSLog(@"unknown Audio Out Format!");
                                break;
                        }
                    }
                    break;
                    
                        //IOTYPE_USER_IPCAM_GETSTREAMCTRL_RESP在摄像机服务端口没有提供服务
                case IOTYPE_USER_IPCAM_GETSTREAMCTRL_RESP:
                    streamQuality = (SMsgAVIoctrlGetStreamCtrlResq *)trash;
                    if (streamQuality->channel == self.ChannelIndex) {
                        switch (streamQuality->quality) {
                                
                            case AVIOCTRL_QUALITY_UNKNOWN:
                                NSLog(@"[Stream Quality] - AVIOCTRL_QUALITY_UNKNOWN");
                                break;
                            case AVIOCTRL_QUALITY_MAX:// ex. 640*480, 15fps, 320kbps (or 1280x720, 5fps, 320kbps)
                                NSLog(@"[Stream Quality] - AVIOCTRL_QUALITY_MAX");
                                break;
                            case AVIOCTRL_QUALITY_HIGH:// ex. 640*480, 10fps, 256kbps
                                NSLog(@"[Stream Quality] - AVIOCTRL_QUALITY_HIGH");
                                break;
                            case AVIOCTRL_QUALITY_MIDDLE:// ex. 320*240, 15fps, 256kbps
                                NSLog(@"[Stream Quality] - AVIOCTRL_QUALITY_MIDDLE");
                                break;
                            case AVIOCTRL_QUALITY_LOW:// ex. 320*240, 10fps, 128kbps
                                NSLog(@"[Stream Quality] - AVIOCTRL_QUALITY_LOW");
                                break;
                            case AVIOCTRL_QUALITY_MIN:	// ex. 160*120, 10fps, 64kbps
                                NSLog(@"[Stream Quality] - AVIOCTRL_QUALITY_MIN");
                                break;
                            default:
                                NSLog(@"unknown stream quality!");
                                break;
                        }
                    }
                    break;
                default:
                    NSLog(@"[RecvIOCtrlLoop] - unkown IOType[%d]!", ioType);
                    break;
            }
        }
        else {
            NSLog(@"[RecvIOCtrlLoop] - unknow ret value.");
        }
    }
}

-(void)CancelConnectDevice{
    
        //关闭所有功能
    [self Video_Stop];
    [self Audio_Stop];
    [self Speak_Stop];
    [self Recorder_Stop];
    [self LED_Off];
    [self Alarm_Off];
    
        //停止相关的线程
    self.LoginSuccessfully = NO;
        //关闭客户端的连接
    avClientStop(self.ChannelIndex);
    NSLog(@"CancelConnectDevice OK");
    IOTC_Session_Close(self.SessionID);
    NSLog(@"IOTC_Session_Close OK");
    avDeInitialize();
    IOTC_DeInitialize();
    NSLog(@"StreamClient exit...");
}

    //MARK: 视频流接收与播放实现区
-(void)Video_Start{
    if(self.LoginSuccessfully){
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_INNER_SND_DATA_DELAY, nil,0);
        if(ret !=AV_ER_NoERROR)
        {
            NSLog(@"Set Inner_Send_Data_Delay Error![%d]",ret);
            return;
        }
        
        SMsgAVIoctrlAVStream sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_START, (char *)&sendMsg, sizeof(SMsgAVIoctrlAVStream));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Video_Start() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Video_Start() Successfully! [%d]",ret);
            self.isVideoStart=YES;
            /*******************/
            VideoAndAudioDecoder * vDecoder = [[VideoAndAudioDecoder alloc] initVideoDecoder];
            
            bufferArray =[NSMutableArray arrayWithCapacity:25];
            lock = [[NSLock alloc] init];
            
            if(vDecoder){
                [NSThread detachNewThreadSelector:@selector(VideoThreadRecvDataToQueue) toTarget:self withObject:nil];
                [NSThread detachNewThreadSelector:@selector(VideoDecoderAndPlayWith:) toTarget:self withObject:vDecoder];
            }
            else
            {
                NSLog(@"Decoder init failed!");
            }
             /*********************/
        }
    }
    else{
        NSLog(@"登录设备不成功，无法开启视频");
    }
}
-(void)VideoThreadRecvDataToQueue{
    NSLog(@"VideoThreadWithDecoder() Starting...");
    char *buf = malloc(VIDEO_BUF_SIZE);
    unsigned int frameNo;
    int ret;
    FRAMEINFO_t frameInfo;
    
    while (self.isVideoStart&&self.LoginSuccessfully) {
        
        ret = avRecvFrameData(self.ChannelIndex, buf, VIDEO_BUF_SIZE, (char*)&frameInfo, sizeof(FRAMEINFO_t), &frameNo);
        
        if(ret == AV_ER_DATA_NOREADY)
        {
            usleep(30000);
            continue;
        }
        else if(ret == AV_ER_LOSED_THIS_FRAME)
        {
            NSLog(@"Lost video frame NO[%d]", frameNo);
            continue;
        }
        else if(ret == AV_ER_INCOMPLETE_FRAME)
        {
            NSLog(@"Incomplete video frame NO[%d]", frameNo);
                //            continue;
        }
        else if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE)
        {
            NSLog(@"[thread_ReceiveVideo] AV_ER_SESSION_CLOSE_BY_REMOTE");
            break;
        }
        else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT)
        {
            NSLog(@"[VideoThreadWithDecoder] AV_ER_REMOTE_TIMEOUT_DISCONNECT");
            break;
        }
        else if(ret == IOTC_ER_INVALID_SID)
        {
            NSLog(@"[VideoThreadWithDecoder] Session cant be used anymore");
            break;
        }
        
        if(ret>0)
        {
            NSLog(@"Frame No. %d, and frame size[%d]",frameNo,ret);
                //解码区
            
            NSData *data = [[NSData alloc] initWithBytes:buf length:ret] ;
            [lock lock];
            if([bufferArray count] < 50){
                [bufferArray addObject:data];
            }else{
                [bufferArray removeObjectAtIndex:0];
            }
            [lock unlock];
        }
    }
    free(buf);
    NSLog(@"[thread_ReceiveVideo] thread exit");
    return ;
}
-(void)VideoDecoderAndPlayWith:(VideoAndAudioDecoder *)videoDecoder{
    
    NSData * popData;
    BOOL needSleep= false;
    
    while (self.isVideoStart && self.LoginSuccessfully) {
        
        [lock lock];
        if ([bufferArray count] > 10) {
            needSleep = false;
            popData = [bufferArray firstObject];
            [bufferArray removeObjectAtIndex:0];
        }else
        {
            needSleep = true;
        }
        [lock unlock];
        
        if(needSleep){
            usleep(1000000);
            continue;
        }
        
        if(popData){
            
            [videoDecoder VideoDecodeWithBuf:(char *)[popData bytes]  BufSize: (int)[popData length]];
            
            UIImage * image=[self convertImageWithAVFrameRGB:videoDecoder.pFrameRGB Width:videoDecoder.pCodecCtx->width Height:videoDecoder.pCodecCtx->height];

            dispatch_async(dispatch_get_main_queue(), ^(){
                [self displayImage:image];
                
            });
            usleep(50000);
        }
    }
    [videoDecoder VideoDecoderDealloc];
}
-(void)Video_Stop{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlAVStream sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_STOP, (char *)&sendMsg, sizeof(SMsgAVIoctrlAVStream));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Video_Stop() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Video_Stop() Successfully! [%d]",ret);
            self.isVideoStart = NO;
        }
    }
    else{
        NSLog(@"登录设备不成功，无法关闭视频");
    }
}

    //MARK:音频流接收与播放实现区
-(void)Audio_Start{
    if(self.LoginSuccessfully){

        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_INNER_SND_DATA_DELAY, nil,0);
        
        if(ret !=AV_ER_NoERROR)
        {
            NSLog(@"Set Inner_Send_Data_Delay Error![%d]",ret);
            return;
        }
        
        SMsgAVIoctrlAVStream sendMsg;
        
        sendMsg.channel= self.ChannelIndex;
        
        ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_AUDIOSTART, (char *)&sendMsg, sizeof(SMsgAVIoctrlAVStream));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Audio_Start() Error! [%d]", ret);
            return ;
            
        }else{
            NSLog(@"Audio_Start() Successfully! [%d]",ret);
            self.isAudioStart = YES;
            /*******************/
             
            /*音频解码器的初始化工作*/
            
            unsigned int frameNo;
            int ret=0;
            FRAMEINFO_t frameInfo;
            
            char buf[AUDIO_BUF_SIZE] = {0};

            while(self.isAudioStart){
                
                ret = avCheckAudioBuf(self.ChannelIndex);
                if (ret < 0){
                    NSLog(@"从设备获取音频帧数据失败");
                    return;
                }
                if (ret < 3) // determined by audio frame rate
                {
                    usleep(120000);
                    continue;
                }
                
                ret = avRecvAudioData(self.ChannelIndex, buf, AUDIO_BUF_SIZE, (char *)&frameInfo, sizeof(FRAMEINFO_t), &frameNo);
                
                if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE)
                {
                    NSLog(@"[AudioThreadWithDecoder] AV_ER_SESSION_CLOSE_BY_REMOTE");
                    return;
                }
                else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT)
                {
                    NSLog(@"[AudioThreadWithDecoder] AV_ER_REMOTE_TIMEOUT_DISCONNECT");
                    return;
                }
                else if(ret == IOTC_ER_INVALID_SID)
                {
                    NSLog(@"[AudioThreadWithDecoder] Session cant be used anymore");
                    return;
                }
                else if (ret == AV_ER_LOSED_THIS_FRAME)
                {
                    continue;
                }
                if(ret >= 0){
                    self.AudioOutFormat = frameInfo.codec_id;//获取音频流格式
                    NSLog(@"第一次读取%d字节",ret);
                break;
                }
            }
            
            switch (self.AudioOutFormat) {
                case MEDIA_CODEC_AUDIO_PCM:
                    NSLog(@"音频格式 - MEDIA_CODEC_AUDIO_PCM[%x]",self.AudioOutFormat);
                    break;
                case MEDIA_CODEC_AUDIO_G711A:
                    NSLog(@"音频格式 - MEDIA_CODEC_AUDIO_G711A[%x]",self.AudioOutFormat);
                    break;
                case MEDIA_CODEC_AUDIO_AAC:
                    NSLog(@"音频格式 - MEDIA_CODEC_AUDIO_AAC[%x]",self.AudioOutFormat);
                    break;
                default:
                    NSLog(@"音频格式- 不支持的音频格式[%x]",self.AudioOutFormat);
                    [self GetAudioOutFormate];
                    return;
            }
            
            if(self.AudioOutFormat == MEDIA_CODEC_AUDIO_AAC){
                
                if(ret < 0)
                {
                    NSLog(@"第一次取数据错误");
                    return;
                }
                
                myData.channelIndex = self.ChannelIndex;
                 
                OSStatus err = AudioFileStreamOpen(&myData, MyPropertyListenerProc, MyPacketsProc,
                                                   kAudioFileAAC_ADTSType, &myData.audioFileStream);
                if (err) {
                    PRINTERROR("AudioFileStreamOpen");
                    return;
                }
                 err = AudioFileStreamParseBytes(myData.audioFileStream, ret-PADDINGBITS, buf+PADDINGBITS, 0);
                if (err ) {
                    NSLog(@"解析数据包错误");
                    return;
                }
                
                [NSThread detachNewThreadSelector:@selector(MPEG2AAC_ADTS_ProcessThread) toTarget:self withObject:nil];

            }
            else
            {
                self.audioDecoder = [[VideoAndAudioDecoder alloc] initAudioDecoderWithFormat:self.AudioOutFormat ChannelIndex:self.ChannelIndex];
            
                [NSThread detachNewThreadSelector:@selector(AudioThreadWithDecoder:) toTarget:self withObject:self.audioDecoder];
                
            /*********************/
            }
        }
    }
    else{
        NSLog(@"登录设备不成功，无法开启音频");
    }
}
-(void)AudioThreadWithDecoder:(VideoAndAudioDecoder *) audioDecoder{
    NSLog(@"[AudioThreadWithDecoder] Starting ...");
    
    if(self.isAudioStart){
        char buf[AUDIO_BUF_SIZE] = {0};
        unsigned int frameNo;
        int ret;
        FRAMEINFO_t frameInfo;
        
        for (int i = 0 ; i < QUEUE_BUFFER_SIZE;i++)
        {
            while(true){
                ret = avCheckAudioBuf(self.ChannelIndex);
                if (ret < 0) return;
                if (ret < 3) // determined by audio frame rate
                {
                    usleep(120000);
                    continue;
                }
                
                ret = avRecvAudioData(self.ChannelIndex, buf, AUDIO_BUF_SIZE, (char *)&frameInfo, sizeof(FRAMEINFO_t), &frameNo);
                
                if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE)
                {
                    NSLog(@"[AudioThreadWithDecoder] AV_ER_SESSION_CLOSE_BY_REMOTE");
                    return;
                }
                else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT)
                {
                    NSLog(@"[AudioThreadWithDecoder] AV_ER_REMOTE_TIMEOUT_DISCONNECT");
                    return;
                }
                else if(ret == IOTC_ER_INVALID_SID)
                {
                    NSLog(@"[AudioThreadWithDecoder] Session cant be used anymore");
                    return;
                }
                else if (ret == AV_ER_LOSED_THIS_FRAME)
                {
                    continue;
                }
                
                    // Now the data is ready in audioBuffer[0 ... ret - 1]
                    // Do something here
                if(ret >= 0){
                    NSLog(@"[i] AAC Packet Data Size is: %d", ret);
                    
                    
                        //二进制输入文件用于分析ADTS包头信息，前24字节
                    
                    [audioDecoder ReadPCMAndPlay:buf+PADDINGBITS  BufSize:ret-PADDINGBITS BufIndex: i];
                        //进行音频解码并播放
                    break;
                }
                else{
                    NSLog(@"没有音频数据");
                }
            }
        }
    }
    NSLog(@"[AudioThreadWithDecoder] Start Play Audio!");
}
-(void)MPEG2AAC_ADTS_ProcessThread{
    
    NSLog(@"[MPEG2AAC_ADTS_ProcessThread] Starting ...");
    
    if(self.isAudioStart){
        char buf[AUDIO_BUF_SIZE] = {0};
        unsigned int frameNo;
        int ret;
        FRAMEINFO_t frameInfo;
        
        for (int i = 0 ; i < kNumAQBufs;i++)
        {
            while(true){
                ret = avCheckAudioBuf(self.ChannelIndex);
                if (ret < 0) return;
                if (ret < 3) // determined by audio frame rate
                {
                    usleep(120000);
                    continue;
                }
                
                ret = avRecvAudioData(self.ChannelIndex, buf, AUDIO_BUF_SIZE, (char *)&frameInfo, sizeof(FRAMEINFO_t), &frameNo);
                
                if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE)
                {
                    NSLog(@"[AudioThreadWithDecoder] AV_ER_SESSION_CLOSE_BY_REMOTE");
                    return;
                }
                else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT)
                {
                    NSLog(@"[AudioThreadWithDecoder] AV_ER_REMOTE_TIMEOUT_DISCONNECT");
                    return;
                }
                else if(ret == IOTC_ER_INVALID_SID)
                {
                    NSLog(@"[AudioThreadWithDecoder] Session cant be used anymore");
                    return;
                }
                else if (ret == AV_ER_LOSED_THIS_FRAME)
                {
                    continue;
                }
                
                    // Now the data is ready in audioBuffer[0 ... ret - 1]
                    // Do something here
                if(ret >= 0){
                    NSLog(@"[i] AAC Packet Data Size is: %d", ret);
                    
                    OSStatus err = AudioFileStreamParseBytes(myData.audioFileStream, ret-PADDINGBITS, buf+PADDINGBITS, 0);
                    if (err ) {
                        NSLog(@"解析数据包错误");
                        return;
                    }
                    
                    myData.fillBufferIndex = i ;
                    break;
                }
            }
        }
    }
    NSLog(@"[MPEG2AAC_ADTS_ProcessThread] Start Play Audio!");
}
-(void)Audio_Stop{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlAVStream sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_AUDIOSTOP, (char *)&sendMsg, sizeof(SMsgAVIoctrlAVStream));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Audio_Stop() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Audio_Stop() Successfully! [%d]",ret);
            self.isAudioStart = NO;
            AudioQueueStop(self.audioDecoder.audioQueue, false);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法关闭音频");
    }
}

    //MARK: 话筒讲话与语音记录实现部分

-(void)Speak_Start{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlAVStream sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_SPEAKERSTART, (char *)&sendMsg, sizeof(SMsgAVIoctrlAVStream));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Speak_Start() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Speak_Start() Successfully! [%d]",ret);
          
            /**
             启动线程传输语音数据到设备
             **/
        }
    }
    else{
        NSLog(@"登录设备不成功，无法开启speak通话");
    }
}
-(void)Speak_Stop{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlAVStream sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_SPEAKERSTOP, (char *)&sendMsg, sizeof(SMsgAVIoctrlAVStream));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Speak_Stop() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Speak_Stop() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法关闭speak通话");
    }
}
-(void)Recorder_Start{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlRecorderCmd sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_RECORDERSTART, (char *)&sendMsg, sizeof(SMsgAVIoctrlRecorderCmd));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Recorder_Start() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Recorder_Start() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法开启视频录制功能");
    }
}
-(void)Recorder_Stop{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlRecorderCmd sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_RECORDERSTOP, (char *)&sendMsg, sizeof(SMsgAVIoctrlRecorderCmd));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Recorder_Stop() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Recorder_Stop() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法停止视频录制功能");
    }
}

    //MARK:简单指令发送区

-(void)LED_On{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlLedCmd sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_LEDON, (char *)&sendMsg, sizeof(SMsgAVIoctrlLedCmd));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"LED_On() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"LED_On() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法打开LED");
    }
}
-(void)LED_Off{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlLedCmd sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_LEDOFF, (char *)&sendMsg, sizeof(SMsgAVIoctrlLedCmd));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"LED_Off() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"LED_Off() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法关闭LED");
    }
}
-(void)Alarm_On{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlAlarmCmd sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_ALARMON, (char *)&sendMsg, sizeof(SMsgAVIoctrlAlarmCmd));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Alarm_On() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Alarm_On() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法开启报警功能");
    }
}
-(void)Alarm_Off{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlAlarmCmd sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_ALARMOFF, (char *)&sendMsg, sizeof(SMsgAVIoctrlAlarmCmd));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"Alarm_Off() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"Alarm_Off() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法关闭报警功能");
    }
}

-(void)SetAudioFormat:(int)format{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlSetAudioFormatReq sendMsg;
        sendMsg.channel= self.ChannelIndex;
        sendMsg.format = format;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_SETAUDIOFORMAT_REQ, (char *)&sendMsg, sizeof(SMsgAVIoctrlSetAudioFormatReq));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"SetAudioFormat() Error! [%d]", ret);
            return ;
        }else{
            switch (format) {
                case MEDIA_CODEC_AUDIO_PCM:
                    NSLog(@"Set Audio Format: PCM  Successfully! [%d]",ret);
                    break;
                case MEDIA_CODEC_AUDIO_G711A:
                    NSLog(@"Set Audio Format: G711A  Successfully! [%d]",ret);
                    break;
                case MEDIA_CODEC_AUDIO_AAC:
                    NSLog(@"Set Audio Format: AAC  Successfully! [%d]",ret);
                    break;
                default:
                    NSLog(@"Set Audio Format: 未知格式  Successfully! [%d]",ret);
                    break;
            }
        }
    }
    else{
        NSLog(@"登录设备不成功，无法设置音频格式");
    }
}
-(void)GetAudioOutFormate{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlGetAudioOutFormatReq sendMsg;
        sendMsg.channel= self.ChannelIndex;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_GETAUDIOOUTFORMAT_REQ, (char *)&sendMsg, sizeof(SMsgAVIoctrlGetAudioOutFormatReq));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"GetAudioOutFormate() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"GetAudioOutFormate() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法获取设备音频输出格式");
    }
}

-(void)SetStreamQuality:(int)quality{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlSetStreamCtrlReq sendMsg;
        sendMsg.channel= self.ChannelIndex;
        sendMsg.quality = quality;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_SETSTREAMCTRL_REQ, (char *)&sendMsg, sizeof(SMsgAVIoctrlSetStreamCtrlReq));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"SetStreamQuality() Error! [%d]", ret);
            return ;
        }else{
            
            NSLog(@"SetStreamQuality() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法设置视频格式");
    }
}
-(void)GetStreamQuality{
    if(self.LoginSuccessfully){
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_GETSTREAMCTRL_REQ, NULL, 0);
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"GetStreamQuality() Error! [%d]", ret);
            return ;
        }else{
            NSLog(@"GetStreamQuality() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法获取设备视频质量");
    }
}

-(void)SetPTZMotionWithCommand:(int)cmd{
    if(self.LoginSuccessfully){
        
        SMsgAVIoctrlPtzCmd sendMsg;
        sendMsg.channel= self.ChannelIndex;
        sendMsg.control=cmd;
        
        int ret = avSendIOCtrl(self.ChannelIndex, IOTYPE_USER_IPCAM_PTZ_COMMAND, (char *)&sendMsg, sizeof(SMsgAVIoctrlPtzCmd));
        
        if (ret != AV_ER_NoERROR)
        {
            NSLog(@"SetPTZMotionWithCommand() Error! [%d]", ret);
            return ;
        }else{
            
            NSLog(@"SetPTZMotionWithCommand() Successfully! [%d]",ret);
        }
    }
    else{
        NSLog(@"登录设备不成功，无法设置云台");
    }
}

@end
